﻿using Brain;
using Brain.Ballistics3D;
using Brain.Bepu;
using Brain.FPS;
using Brain.Logic3D.PathFinding;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using SynapseGaming.LightingSystem.Lights;
using SynapseGaming.LightingSystem.Shadows;
using Brain.Skinning;
using SynapseGaming.LightingSystem.Rendering;
using Brain.SunBurn;

namespace Sample_Game
{
    public class MainGameScreen : GameScreen
    {
        public WeaponDatabase Weapons;
        // Database of PLAYABLE characters
        public CharacterDatabase Characters;
        // Database of Non-Playable characters(which could be enemies
        // or friendlies)
        public NPCDatabase Enemies;

        public Map3D Map;

        public BulletManager3D BulletManager;
        Effect effect;

        public MainGameScreen()
        {
            Engine.Instance.OnDevelopment = true;

            Weapons = new WeaponDatabase();
            Characters = new CharacterDatabase();
            Enemies = new NPCDatabase();                        

            {
                // Weapons
                WeaponInfo RA332Info = new WeaponInfo();
                RA332Info.Name = "RA332";
                RA332Info.ModelPlace = "skin:Models\\weapons\\ra332";
                //RA332Info.ScopePosition = new Vector3(1, -3.2f, -3);
                RA332Info.ScopePosition = new Vector3(1, -2.5f, -3);
                RA332Info.ShotPosition = new Vector3(0, 2.5f, -10);
                RA332Info.BulletSpeed = 400;
                RA332Info.MsBetweenShots = 300;
                RA332Info.ClipSize = 50;
                Weapons.Variables.Add(RA332Info);
            }
            {
                //Characters
                CharacterInfo MainChar = new CharacterInfo();
                MainChar.WeaponPosition = new Vector3(3, -3, -6);
                MainChar.ScopeSpeed = 15;
                MainChar.WalkSpeed = 60;
                MainChar.RunSpeed = 120;
                MainChar.StandingCameraOffset = 15;
                Characters.Variables.Add(MainChar);
            }
            {
                // NPCs
                // Just 1 enemy for the sample
                NPCInfo enemy = new NPCInfo();
                enemy.ModelPlace = "Models\\enemy";
                
                Enemies.Variables.Add(enemy);
            }

            BrainModel model = ModelUtil.GenerateCylinderMesh(1, 1, 24);
            BrainModelMesh mesh = model.Meshes[0];
            effect = Engine.Instance.ContentManager.Load<Effect>("Effects/Bullet");
            DefaultBulletRendererModel3D renderer = new DefaultBulletRendererModel3D(
                mesh.VertexBuffer, mesh.IndexBuffer, effect);

            BulletManager = new BulletManager3D(100);
            BulletManager.BulletRenderer = renderer;
            

            BepuPhysicsManager physics = Engine.Instance.Physics3DManager as BepuPhysicsManager;
            physics.Gravity = new Vector3(0, -40, 0);

            // Load Map with materials and stuff
            WorldObject ground = new WorldObject("Models\\map_vis");
            ground.Rendering = WorldObjectRendering.Rendered;
            // Load 1st version of map, with walls, for collision
            PhysicObject_TriangleMesh triMesh = new PhysicObject_TriangleMesh("Models\\map_bepu", physics.Space);
            ground.PhysicsObject = triMesh;

            // Load 2nd version of map, without walls, for AI Path Finding
            Model mapModel = Engine.Instance.ContentManager.Load<Model>("Models\\map_ai");
            Vector3[] vertices;
            int[] indices;
            // Extract data from Model
            TriangleUtil.GetVerticesAndIndicesFromModel(mapModel, out vertices, out indices);
            // Brain Map System CURRENTLY does not work with indices.
            // So we need to get an array with all the vertices
            vertices = TriangleUtil.GetAllVertices(vertices, indices);
            Map = new Map3D(2, vertices);

            SynapseGaming.LightingSystem.Lights.DirectionalLight DirLight = new SynapseGaming.LightingSystem.Lights.DirectionalLight();
            DirLight.Direction = new Vector3(0.5f, -1, 0.5f);
            DirLight.Intensity = 1f;
            DirLight.ShadowType = ShadowType.AllObjects;
            DirLight.ShadowQuality = 10;// ULTRA MAX haha wish I could(limit is 2)
            DirLight.Direction = new Vector3(0, -0.7f, 0.85f);
            DirLight.DiffuseColor = Color.White.ToVector3();
            DirLight.ShadowPrimaryBias = 1.0f;
            DirLight.ShadowSecondaryBias = 0.04f;
            Engine.Instance.RenderManager3D.SubmitLight(DirLight);

            AmbientLight ambLight = new AmbientLight();
            ambLight.Intensity = 0.5f;
            Engine.Instance.RenderManager3D.SubmitLight(ambLight);

            PlayerInfo info = new PlayerInfo();
            info.PlayerIndex = Microsoft.Xna.Framework.PlayerIndex.One;
            controller = new GamerController(info, Characters.Variables[0] as CharacterInfo, 18, 3);
            controller.Weapon.Weapons.Add(new Weapon(0));
            controller.Input.SetPosition(new Vector3(0, 100, 0));
            this.AddComponent(controller);

            ground.Update();
            ground.Draw();

            IRenderManager3D render = Engine.Instance.RenderManager3D;
            render.AfterRenderActions.Add(BulletManager.Draw);

            DOF = new DepthOfFieldPostProcessor();
            DOF.BlurAmount = 5;
            render.Submit(DOF);
        }
        GamerController controller;
        DepthOfFieldPostProcessor DOF;

        public override void Update()
        {
            base.Update();

            BulletManager.Update();

            if (controller.IsScoping)
            {
                DOF.SetMaxDepth(10f, Engine.Instance.CameraManager.Camera3D.FarPlane);
            }
            else
            {
                DOF.MaxDepth = 0;
            }
        }

        public override void Draw()
        {
            base.Draw();

            if (Engine.Instance.CameraManager.Camera3D != null)
            {
                effect.Parameters["View"].SetValue(Engine.Instance.CameraManager.Camera3D.View);
                effect.Parameters["Projection"].SetValue(Engine.Instance.CameraManager.Camera3D.Projection);
            }
        }
    }
}
